/*
 *	Archimedes specific file - M. Andreasen 1990
 */

#include "vi.h"
#include <string.h>
#include <kernel.h>
#include <sys/types.h>
#include <sys/stat.h>

/*	this file is needed since the arc does not have a escape sequence
 *	type of screen handler. 
 */

static char str[256],gotos[20],_ESC[10],work[80];
static int _ESC_SET=0;
static char col_f=-1,col_b=-1;

/* find the cursor postion - needed for inserts and delete where a window is
 * defined and then scrolled in the required direction
 */
		
static void convert(path)
char *path;
{
	char	s[256];
	int	len,i;

	len=strlen(path);
	if (path[len-2]!='.' || len<3) return;
	i=len-3;
	path[len-2]=NULL;
	while (path[i]!='.' && i>=0) --i;
	if (i<0) {
		sprintf(s,"%c.%s",path[len-1],path);
	} else {
		path[i]=NULL;
		sprintf(s,"%s.%c.%s",path,path[len-1],path+i+1);
	}
	strcpy(path,s);
}

void get_pos(x,y)
int *x,*y;
{
      int r;

      r=_kernel_osbyte(134,0,0);
      *x=r&0xff;
      *y=(r>>8)&0xff;
}

/* used for creating unique filenames. multi user systems ? */

int rnd()
{
	return(rand()&0xfff);
}

/* Arch version of an escape sequence */

void vdu(char *seq)
{
	char *p;
	int x;

	p=strtok(seq,",");
	while (p!=NULL) {
		x=atoi(p);
		_kernel_oswrch(x);
		p=strtok(NULL,",");
	}
}

/* insert character */

void A_IC()
{
      int x,y;

      get_pos(&x,&y);
      sprintf(str,"28,%d,%d,%d,%d,23,7,0,0,0,0,0,0,0,0,26,31,%d,%d",x,y,79,y,x,y);
	vdu(str);
	_ESC_SET=0;
}

/* delete character */

void A_DC()
{
      int x,y;

      get_pos(&x,&y);
      sprintf(str,"28,%d,%d,%d,%d,23,7,0,1,0,0,0,0,0,0,26,31,%d,%d",x,y,79,y,x,y);
	vdu(str);
	_ESC_SET=0;
}

/* insert line */

void A_IL()
{
      int x,y;

      get_pos(&x,&y);
      sprintf(str,"28,%d,%d,%d,%d,23,7,0,2,0,0,0,0,0,0,26,31,%d,%d",0,31,79,y,x,y);
	vdu(str);
	_ESC_SET=0;
}

/* delete line */

void A_DL()
{
      int x,y;

      get_pos(&x,&y);
      sprintf(str,"28,%d,%d,%d,%d,23,7,0,3,0,0,0,0,0,0,26,31,%d,%d",0,31,79,y,x,y);
	vdu(str);
	_ESC_SET=0;
}

/* clear to end of line */

void A_CE()
{
	sprintf(str,"23,8,5,6,0,0,0,0,0,0");
	vdu(str);
	_ESC_SET=0;
}

/* scroll reverse */

void A_SR()
{
	sprintf(str,"23,7,1,2,0,0,0,0,0,0");
	vdu(str);
	_ESC_SET=0;
}

/* clear screen and home */

void A_CL()
{
	sprintf(str,"12,30");
	vdu(str);
	_ESC_SET=0;
}

/* visual bell - not very visable ? */

void A_VB()
{
	_kernel_oswrch(7);
	_ESC_SET=0;
}

/* you guessed it - up ! */

void A_UP()
{
	_kernel_oswrch(11);
	_ESC_SET=0;
}

/* process a two character escape code */

void check_esc1()
{
	if (strcmp("VB",_ESC)==0) A_VB();
	if (strcmp("UP",_ESC)==0) A_UP();
	if (strcmp("CE",_ESC)==0) A_CE();
	if (strcmp("CL",_ESC)==0) A_CL();
	if (strcmp("DL",_ESC)==0) A_DL();
	if (strcmp("SR",_ESC)==0) A_SR();
	if (strcmp("IL",_ESC)==0) A_IL();
	if (strcmp("IC",_ESC)==0) A_IC();
	if (strcmp("DC",_ESC)==0) A_DC();
}

/* a cursor movement sequence or an invalid sequence */

void check_esc2()
{
	int x,y;

	if (strncmp("CM",_ESC,2)!=0) {
		printf("BAD escape sequence (%s)\n",_ESC);
		exit(1);
	} else {
		x=_ESC[2]-' ';
		y=_ESC[3]-' ';
		_kernel_oswrch(31);
		_kernel_oswrch(x);
		_kernel_oswrch(y);
		_ESC_SET=0;
	}
}

/* output a character or build an escape sequence */

void outchar(c)
char c;
{
	int l;

	if (o_colourf[0]!=col_f) {
		col_f=o_colourf[0];
		_kernel_oswrch(17);
		_kernel_oswrch(col_f);
	}
	if (o_colourb[0]!=col_b) {
		col_b=o_colourb[0];
		_kernel_oswrch(17);
		_kernel_oswrch(col_b+128);
	}
	if (c==27) {
		_ESC[0]=NULL;
		_ESC_SET=1;
	} else {
		if (_ESC_SET) {
			l=strlen(_ESC);
			_ESC[l]=c;
			_ESC[l+1]=NULL;
			if (l==1) check_esc1();
			if (l==3) check_esc2();
		} else {
			_kernel_oswrch(c);
		}
	}
}


/* this is the UNIX hook to the termial infomation required in the 
 * curses library. this is hardwired for the Arc. */

char *tputs(s,lines,func)
void func(char);
int lines;
char *s;
{
      register int x=0;

	while (s[x]!=NULL) {
		func(s[x]);
		x++;
	}
	return(s);
}

char *tgoto(a,x,y)
char *a;
int x,y;
{
      sprintf(gotos,"\033CM%c%c",' '+x,' '+y);
      return(gotos);
}

void ARC_keyword(word)
char *word;
{
	sprintf(work,"%s %s",o_keywordprg,word);
	system(work);
}

/* 	the following are functions that are called from various parts of
 *	vi. I don't know what they are do, but most of them appear to
 * 	be in connection with system() and piping between programs - not
 * 	on the arc
 */

 /* this should really be implemented !! */

int dup()
{
    return(-1);
}

link()
{
    printf("Abort - link called\n");
    exit(1);
}

execl()
{
    printf("Abort - execl called\n");
    exit(1);
}

fstat()
{
    printf("Abort - fstat called\n");
    exit(1);
}

alarm()
{
    printf("Abort - alarm called\n");
    exit(1);
}

pipe()
{
    printf("Abort - pipe called\n");
    exit(1);
}

wait()
{
    printf("Abort - wait called\n");
    exit(1);
}

execle()
{
    printf("Abort - execle called\n");
    exit(1);
}

fork()
{
    printf("Abort - fork called\n");
    exit(1);
}

environ()
{
    printf("Abort - environ called\n");
    exit(1);
}

int getpid()
{
    return(rnd());
}

int geteuid()
{
    return(rnd());
}

/* I don't know what ctype ascii is but this seems to work */

int isascii(c)
int c;
{
     return(isprint(c));
}

/*	the following functions are low level UNIX functions for
 *	creating, opening, reading, writing and seeking.
 *	handle number lower that 3 appear to be screen and keyboard
 *	based so thats what I have made the following do
 */

/* seek to a postion in a file */

int lseek(fd,off,mode)
int fd,off,mode;
{
     int l;

	/* 0 - seek from start of file
	   2 - seek from end of file */

      switch (mode) {
           case 0:
                return(_kernel_osargs(1,fd,off));
           case 2:
                 l=_kernel_osargs(2,fd,0);
                 return(_kernel_osargs(1,fd,l-off));
           default:
		/* did not occur while testing ? */

                printf("lseek: mode=%d, offset=%d\n",mode,off);
		exit(1);
	}
	return(0);
}

int open(file,mode)
char *file;
int mode;
{
	int 	handle;

	convert(file);
	handle = _kernel_osfind(195,file);
	if (handle==0) {
		errno=2;
		return(-1);
	}
	errno=0;
	return(handle);
}

int creat(file,mode)
char *file;
int mode;
{
	int 		handle,type=0;
	struct stat	st;

	convert(file);
	if (stat(file,&st)>=0) type=st.st_type;
	handle = _kernel_osfind(131,file);
	if (handle>0) {
		stat(file,&st);
		if (type==0) st.st_type=4095;
		set_stat(file,&st);
	}
	return(handle);
}

int close(handle)
int handle;
{
	if (handle>2)
		_kernel_osfind(0, (char *)handle);
	return(0);
}

/* delete a file */

unlink(file)
char *file;
{
      remove(file);
}

/* UNIX low level write */

int write (h,b,l)
char *b;
int l,h;
{
	register int	i;

	if (h<3 && h>=0) for (i=0; i<l; i++) outchar(b[i]);
	else for (i=0; i<l; i++) {
		if (_kernel_osbput(b[i],h) < 0) return(-1);
	}
	return(l);
}

/* UNIX low level read */

int read (h,b,l)
char *b;
int l,h;
{
	register int 	i;
	int	c;

	if (h<3 && h>=0) {
		b[0]=_kernel_osrdch();
		return(1);
	} else {
		for (i=0; i<l; i++) {
			c=_kernel_osbget(h);
			if (c<0) return(i);
			b[i]=c;
		}
	}
	return(l);
}

